package com.fly.core.ds;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ResourceBundle;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import org.apache.tomcat.jdbc.pool.DataSource;
import org.apache.tomcat.jdbc.pool.PoolProperties;

import lombok.extern.slf4j.Slf4j;

/**
 * 
 * 数据源(tomcat-jdbc-pool)管理工具
 * 
 * @author 00fly
 * @version [版本号, 2018-09-26]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Slf4j
public class JDBCPool extends BaseDataSource
{
    private static DataSource dataSource = new DataSource();
    
    /**
     * <默认构造函数>
     */
    private JDBCPool()
    {
        super();
    }
    
    // 静态初始化 DataSource
    static
    {
        ResourceBundle config = ResourceBundle.getBundle("jdbc");
        PoolProperties p = new PoolProperties();
        p.setUrl(config.getString("jdbc.url"));
        p.setDriverClassName(config.getString("jdbc.driver"));
        p.setUsername(config.getString("jdbc.username"));
        p.setPassword(config.getString("jdbc.password"));
        p.setFairQueue(true);// 异步获取连接,必须将fairQueue设置为true
        p.setJmxEnabled(true);
        p.setTestWhileIdle(false);
        p.setTestOnBorrow(true);
        p.setValidationQuery("SELECT 1");
        p.setTestOnReturn(false);
        p.setValidationInterval(30000);
        p.setTimeBetweenEvictionRunsMillis(30000);
        p.setMaxActive(100);
        p.setInitialSize(10);
        p.setMaxWait(10000);
        p.setRemoveAbandonedTimeout(60);
        p.setMinEvictableIdleTimeMillis(30000);
        p.setMinIdle(10);
        p.setLogAbandoned(true);
        p.setRemoveAbandoned(true);
        p.setJdbcInterceptors("org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer");
        dataSource.setPoolProperties(p);
    }
    
    private static final JDBCPool SINGLE = new JDBCPool();
    
    /**
     * 单例获取对象
     * 
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static JDBCPool getInstance()
    {
        return SINGLE;
    }
    
    /**
     * 获取数据库连接
     * 
     * @return
     * @throws SQLException
     * @throws ExecutionException
     * @throws InterruptedException
     * @see [类、类#方法、类#成员]
     */
    @Override
    public Connection getConnection()
        throws SQLException
    {
        try
        {
            Connection connection = threadLocal.get();
            if (connection == null)
            {
                Future<Connection> future = dataSource.getConnectionAsync();
                while (!future.isDone())
                {
                    try
                    {
                        TimeUnit.MICROSECONDS.sleep(100);
                    }
                    catch (InterruptedException iex)
                    {
                        Thread.currentThread().interrupt();
                        log.error(iex.getMessage(), iex);
                    }
                }
                connection = future.get();
                threadLocal.set(connection); // 把 connection绑定到当前线程上
            }
            log.info("★★★★申请资源: {}", connection);
            return connection;
        }
        catch (Exception e)
        {
            throw new SQLException(e.getMessage(), e.getCause());
        }
    }
}
